home *** CD-ROM | disk | FTP | other *** search
/ Mac Expert 1995 Winter / Mac Expert - Winter 95.iso / Les fichiers / Communications / Internet / TurboTCP 2.1 ƒ / TCL MiniTelnet source / CTelnetTerminal.cp < prev    next >
Encoding:
Text File  |  1995-01-04  |  12.8 KB  |  659 lines  |  [TEXT/MMCC]

  1. /*
  2. ** CTelnetTerminal.cp
  3. **
  4. **    MiniTelnet application
  5. **    Telnet terminal session document
  6. **
  7. **    Copyright © 1993-94, FrostByte Design / Eric Scouten
  8. **
  9. */
  10.  
  11.  
  12. #include "CTelnetTerminal.h"
  13.  
  14. #include "CBartender.h"
  15. #include "CClipboard.h"
  16. #include "CDecorator.h"
  17. #include "CDesktop.h"
  18. #include "CScrollPane.h"
  19. #include "Commands.h"
  20. #include "TCLUtilities.h"
  21.  
  22. #include "CTerminalPane.h"
  23.  
  24.  
  25. //    —— TCL globals ——
  26.  
  27. extern CBartender*    gBartender;
  28. extern CClipboard*    gClipboard;
  29. extern CDecorator*    gDecorator;
  30. extern CDesktop*    gDesktop;
  31.  
  32. TCL_DEFINE_CLASS_M2(CTelnetTerminal, CDocument, CTelnetInterp);
  33.  
  34.  
  35. //    —— constructor ——
  36.  
  37. /*______________________________________________________________________
  38. **
  39. ** constructor
  40. **
  41. **    Initialize the Telnet terminal session document.
  42. **
  43. **        theDefaultPort (unsigned short):    default IP port number
  44. **        recBufferSize (unsigned long):        size of the receive buffer we need
  45. **        autoReceiveSize (unsigned long):    number of entries in RDS for auto-receive,
  46. **                                        0 to disable autoreceiving
  47. **        autoReceiveNum (unsigned short):    number of auto-receive calls to issue at once
  48. **                                        must be at least 1
  49. **        doUseCName (unsigned Boolean):    TRUE to look up canonical names for hosts
  50. **        printable (Boolean):                TRUE if document is printable
  51. **
  52. */
  53.  
  54. CTelnetTerminal::CTelnetTerminal(unsigned short theDefaultPort, unsigned long recBufferSize,
  55.                             unsigned short autoReceiveSize, unsigned short autoReceiveNum,
  56.                             Boolean doUseCName, Boolean printable)
  57.  
  58.     : CDocument(printable),
  59.       CTelnetInterp(theDefaultPort, recBufferSize, autoReceiveSize, autoReceiveNum, doUseCName)
  60.  
  61. {
  62.     itsTerminal = NULL;
  63.     itsTermMode = 0;
  64.     showFileName = FALSE;
  65. }
  66.  
  67.  
  68. //    —— creating new sessions ——
  69.  
  70. /*______________________________________________________________________
  71. **
  72. ** NewSession
  73. **
  74. **    Create a new window for document. Pulls information from the settings record which
  75. **    it receives and opens a session accordingly.
  76. **
  77. **        theSettings (TelnetSettingsRec*):    the settings record to use
  78. **
  79. */
  80.  
  81. void CTelnetTerminal::NewSession(TelnetSettingsRec* theSettings)
  82.  
  83. {
  84.     // copy the settings record
  85.     
  86.     BlockMove(theSettings, &r, sizeof (TelnetSettingsRec));
  87.     BlockMove(r.hostName, hostCName, 256);
  88.     goAwayOnClose = r.closeOnSessionEnd;
  89.     showDebug = r.showDebug;
  90.     
  91.  
  92.     // build a window immediately
  93.     
  94.     BuildWindow();
  95.     
  96.  
  97.     // open host by name
  98.     
  99.     #if _TestTerminal
  100.         itsTerminal->DoWriteStr("No TCP session. Just type onto terminal.\r\n");
  101.     #else
  102.         SetOpenTimeout(20);
  103.         OpenUserHost((char*) r.hostName, defaultPort, TRUE);
  104.     #endif
  105.  
  106. }
  107.  
  108.  
  109. /*______________________________________________________________________
  110. **
  111. ** BuildWindow
  112. **
  113. **    Build a window for a terminal connection.
  114. **
  115. */
  116.  
  117. void CTelnetTerminal::BuildWindow()
  118.  
  119. {
  120.     CScrollPane*        theScrollPane;
  121.     CTerminalPane*    theMainPane;
  122.     Rect                sizeRect;
  123.     
  124.  
  125.     // create a window
  126.  
  127.     itsWindow = new CWindow(WINDTelnet, FALSE, this);
  128.  
  129.  
  130.     // set maximum size of window
  131.  
  132.     SetRect(&sizeRect, 100, 100, sizeX+16, sizeY+16);
  133.     itsWindow->SetSizeRect(&sizeRect);
  134.  
  135.  
  136.     // create the scrolling pane
  137.  
  138.     theScrollPane = new CScrollPane(itsWindow, this, 10, 10, 0, 0,
  139.                             sizELASTIC, sizELASTIC, TRUE, TRUE, TRUE);
  140.     theScrollPane->FitToEnclFrame(TRUE, TRUE);
  141.  
  142.  
  143.     // create the main view pane
  144.  
  145.     theMainPane = new CTerminalPane(theScrollPane, this, 0, 0, 0, 0, sizELASTIC, sizELASTIC);
  146.     itsMainPane = theMainPane;
  147.     itsTerminal = theMainPane;
  148.     itsGopher = theMainPane;
  149.     theMainPane->FitToEnclosure(TRUE, TRUE);
  150.  
  151.  
  152.     // make sure the scroll pane knows about the panorama
  153.  
  154.     theScrollPane->InstallPanorama(theMainPane);
  155.     
  156.  
  157.     // place, size, and title the window
  158.  
  159.     gDecorator->PlaceNewWindow(itsWindow);
  160.     StateChanged();
  161.     itsWindow->Select();
  162.  
  163. }
  164.  
  165.  
  166. // —— closing windows & sessions ——
  167.  
  168. /*______________________________________________________________________
  169. **
  170. ** Close
  171. **
  172. **    Respond to user close. Ensure that the TCP stream is gracefully closed. (This method is
  173. **    also called if the remote host closes the session or the session is terminated.)
  174. **
  175. **        quitting (Boolean):    TRUE if quitting
  176. **
  177. **        return (Boolean):    FALSE if close/quit aborted by user
  178. **
  179. */
  180.  
  181. Boolean CTelnetTerminal::Close(Boolean quitting)
  182.  
  183. {
  184.     closeAndQuit = quitting;                        // do we really want to close?
  185.     if (!ConfirmClose(quitting))
  186.         return FALSE;
  187.  
  188.     if (itsFile)                                    // close file first
  189.         itsFile->Close();
  190.  
  191.     if (!LocalClose(quitting))                        // now close stream
  192.         return FALSE;
  193.  
  194.     return CDirector::Close(quitting);
  195.  
  196. }
  197.  
  198.  
  199. /*______________________________________________________________________
  200. **
  201. ** RemoteClose
  202. **
  203. **    Respond to notification that the remote host cancelled the session (either by normal
  204. **    close or terminate).
  205. **
  206. */
  207.  
  208. void CTelnetTerminal::RemoteClose()
  209.  
  210. {
  211.     Boolean sessionWasEstablished = SessionEstablished();
  212.  
  213.     CTelnetInterp::RemoteClose();
  214.     if ((goAwayOnClose) && (!sessionWasEstablished))
  215.         Close(FALSE);
  216. }
  217.  
  218.  
  219. //    —— window titling ——
  220.  
  221. /*______________________________________________________________________
  222. **
  223. ** SetWindowTitle
  224. **
  225. **    Sets title for window. Turns on or off cursor blinking depending on whether session
  226. **    is established.
  227. **
  228. **        newTitle (Str255):    the new title for the window
  229. **
  230. */
  231.  
  232. void CTelnetTerminal::SetWindowTitle(Str255 newTitle)
  233.  
  234. {
  235.     if (itsWindow)
  236.         itsWindow->SetTitle(newTitle);
  237.     itsTerminal->SetBlinking(SessionEstablished());
  238. }
  239.  
  240.  
  241. //    —— command/event handling ——
  242.  
  243. /*______________________________________________________________________
  244. **
  245. ** DoCommand
  246. **
  247. **    Handle all commands document can understand.
  248. **
  249. **        theCommand (long):    command number that was issued
  250. **
  251. */
  252.  
  253. void CTelnetTerminal::DoCommand(long theCommand)
  254.  
  255. {
  256.     char addrStr[18];                        // used for send IP addr command
  257.     
  258.     switch (theCommand) {
  259.     
  260.         // Edit menu: support pasting TEXT
  261.         
  262.         case cmdPaste:
  263.             DoPaste();
  264.             break;
  265.         
  266.         // Telnet menu: send various strings to server
  267.         
  268.         case cmdSendSynch:
  269.             if (showDebug)
  270.                 PrintDebugStr("{Urgent IAC DM}");
  271.             SetNextUrgent();
  272.             *this << "\377\362";
  273.             break;
  274.  
  275.         case cmdSendBreak:
  276.             if (showDebug)
  277.                 PrintDebugStr("{Urgent IAC BRK IAC DM}");
  278.             SetNextUrgent();
  279.             *this << "\377\363\377\362";
  280.             break;
  281.             
  282.         case cmdSendAO:
  283.             if (showDebug)
  284.                 PrintDebugStr("{Urgent IAC AO IAC DM}");
  285.             SetNextUrgent();
  286.             *this << "\377\365\377\362";
  287.             break;
  288.             
  289.         case cmdSendIP:
  290.             if (showDebug)
  291.                 PrintDebugStr("{Urgent IAC IP IAC DM}");
  292.             SetNextUrgent();
  293.             *this << "\377\364\377\362";
  294.             break;
  295.             
  296.         case cmdSendAYT:
  297.             if (showDebug)
  298.                 PrintDebugStr("{Urgent IAC AYT IAC DM}");
  299.             SetNextUrgent();
  300.             *this << "\377\366\377\362";
  301.             break;
  302.             
  303.         case cmdSendGA:
  304.             if (showDebug)
  305.                 PrintDebugStr("{IAC GA}");
  306.             *this << "\377\371";
  307.             break;
  308.             
  309.         case cmdSendEC:
  310.             if (showDebug)
  311.                 PrintDebugStr("{IAC EC}");
  312.             *this << "\377\367";
  313.             break;
  314.             
  315.         case cmdSendEL:
  316.             if (showDebug)
  317.                 PrintDebugStr("{IAC EL}");
  318.             *this << "\377\370";
  319.             break;
  320.             
  321.         case cmdSendIPAddr:
  322.             *this << local_IP;
  323.             break;
  324.  
  325.         case cmdShowDebug:
  326.             showDebug = !showDebug;
  327.             r.showDebug = showDebug;
  328.             break;
  329.             
  330.         // not ours, send along the chain
  331.         
  332.         default:
  333.             CDocument::DoCommand(theCommand);
  334.     }
  335. }
  336.  
  337.  
  338. /*______________________________________________________________________
  339. **
  340. ** DoKeyDown
  341. **
  342. **    Process key-down events. Parses CR, LF codes and generates the
  343. **    standard CR/LF sequence when CR is passed and ignores LF.
  344. **
  345. **        theChar (char):                the character that was entered
  346. **        keyCode (byte):            the Mac ADB key number for the key that was pressed
  347. **        macEvent (EventRecord*):    the entire event record
  348. **
  349. */
  350.  
  351. void CTelnetTerminal::DoKeyDown(char theChar, Byte keyCode, EventRecord* macEvent)
  352.  
  353. {
  354.  
  355.     // make sure this isn’t an errant command key
  356.     
  357.     if (!((*macEvent).modifiers & cmdKey)) {
  358.         if (theChar != charLF) {
  359.             #if _TestTerminal
  360.                 HandleNVTChar(theChar);
  361.                 if (theChar == charCR)
  362.                     HandleNVTChar(charLF);
  363.             #else
  364.                 if (!SessionEstablished()) {
  365.                     SysBeep(0);
  366.                     return;
  367.                 }
  368.         
  369.                 if (theChar == charBS)
  370.                     SendChar(r.backspaceChar);
  371.                 else
  372.                     SendChar(theChar);
  373.         
  374.                 if (theChar == charCR)
  375.                     SendChar(charLF);
  376.             #endif
  377.         itsTerminal->ScrollToSelection();
  378.         }
  379.     }
  380.  
  381. }
  382.  
  383.  
  384. /*______________________________________________________________________
  385. **
  386. ** DoPaste
  387. **
  388. **    Respond to Paste command by sending all characters from the
  389. **    clipboard to the remote host.
  390. **
  391. */
  392.  
  393. void CTelnetTerminal::DoPaste()
  394.  
  395. {
  396.     Handle    theData;
  397.     char        lineBfr[83];
  398.     char        *p, *pl, *lb;
  399.     long        rem;
  400.     short    i;
  401.     
  402.     // get the clipboard contents
  403.     
  404.     if (!(gClipboard->GetData('TEXT', &theData)))
  405.         return;
  406.     HLock(theData);
  407.     
  408.     // send it in line or 80-char chunks
  409.     
  410.     p = (char*) *theData;
  411.     rem = GetHandleSize(theData);
  412.     
  413.     while (rem > 0) {
  414.     
  415.         // fetch a line (or 81 chars)
  416.         
  417.         i = 0;
  418.         pl = p;
  419.         lb = lineBfr;
  420.         while ((rem-(i) > 0) && (*pl != charCR) && (i < 80))
  421.             i++, *lb++ = *pl++;
  422.         if (*pl == charCR) {
  423.             i++, *pl++;
  424.             *lb++ = charCR;
  425.             *lb++ = charLF;
  426.         }
  427.         *lb = '\0';
  428.     
  429.         // send the line
  430.         
  431.         #if _TestTerminal
  432.             HandleNVTLine(lineBfr);
  433.         #else
  434.             *this << lineBfr;
  435.         #endif
  436.     
  437.         rem -= i;
  438.         p += i;
  439.         
  440.     }
  441.     
  442.     HUnlock(theData);
  443.     DisposHandle(theData);
  444. }
  445.  
  446.  
  447. /*______________________________________________________________________
  448. **
  449. ** UpdateMenus
  450. **
  451. **    Enable Telnet-specific commands.
  452. **
  453. */
  454.  
  455. void CTelnetTerminal::UpdateMenus()
  456.  
  457. {
  458.     CDocument::UpdateMenus();
  459.     
  460.     // enable “Paste” command only if valid Clipboard
  461.     
  462.     #if _TestTerminal
  463.         if (gClipboard->DataSize('TEXT'))
  464.             gBartender->EnableCmd(cmdPaste);
  465.     #else
  466.         if (SessionEstablished() && (gClipboard->DataSize('TEXT')))
  467.             gBartender->EnableCmd(cmdPaste);
  468.     #endif
  469.  
  470.     
  471.     // enable “Send…” commands only if session is active
  472.  
  473.     if (SessionEstablished()) {
  474.         gBartender->EnableCmd(cmdSendSynch);
  475.         gBartender->EnableCmd(cmdSendBreak);
  476.         gBartender->EnableCmd(cmdSendAO);
  477.         gBartender->EnableCmd(cmdSendIP);
  478.         gBartender->EnableCmd(cmdSendAYT);
  479.         gBartender->EnableCmd(cmdSendGA);
  480.         gBartender->EnableCmd(cmdSendEC);
  481.         gBartender->EnableCmd(cmdSendEL);
  482.         gBartender->EnableCmd(cmdSendIPAddr);
  483.         gBartender->EnableCmd(cmdShowDebug);
  484.         gBartender->CheckMarkCmd(cmdShowDebug, showDebug);
  485.     }
  486.  
  487. }
  488.  
  489.  
  490. //    —— Telnet command handling ——
  491.  
  492. /*______________________________________________________________________
  493. **
  494. ** ReceivedDo
  495. **
  496. **    Respond to a Telnet [IAC DO option] sequence.
  497. **
  498. **        theOption (uchar):    the option code
  499. **
  500. */
  501.  
  502. void CTelnetTerminal::ReceivedDo(uchar theOption)
  503.  
  504. {
  505.     char respondStr[4];
  506.     
  507.     // parse the option and respond to it
  508.     
  509.     switch (theOption) {
  510.     
  511.         // accept terminal type option only
  512.         
  513.         case optTERMINAL_TYPE:
  514.             respondStr[0] = charIAC;
  515.             respondStr[1] = escWILL;
  516.             respondStr[2] = theOption;
  517.             respondStr[3] = '\0';
  518.             if (showDebug) {
  519.                 PrintDebugStr("{IAC WILL");
  520.                 PrintDebugCharNum(theOption, ' ', '}');
  521.             }
  522.             *this << respondStr;
  523.             break;
  524.         
  525.         // reject the remaining options
  526.         
  527.         default:
  528.             CTelnetInterp::ReceivedDo(theOption);
  529.     }
  530.  
  531. }
  532.  
  533.  
  534. /*______________________________________________________________________
  535. **
  536. ** ReceivedAYT
  537. **
  538. **    Respond to a Telnet [IAC AYT] sequence.
  539. **
  540. */
  541.  
  542. void CTelnetTerminal::ReceivedAYT()
  543.  
  544. {
  545.     if (showDebug)
  546.         PrintDebugStr("{Yes}");
  547.     *this << "[Yes]";
  548. }
  549.  
  550.  
  551. /*______________________________________________________________________
  552. **
  553. ** ReceivedSE
  554. **
  555. **    Parse subnegotiation parameters. Called when [IAC SE] is received.
  556. **
  557. */
  558.  
  559. void CTelnetTerminal::ReceivedSE()
  560.  
  561. {
  562.     // dispatch to an option-parsing routine
  563.     
  564.     if (sbBfrIndex < 1)
  565.         return;
  566.     switch (sbBfr[0]) {
  567.  
  568.         case optTERMINAL_TYPE:
  569.             OptionTerminalType();
  570.             break;
  571.         
  572.         default:
  573.             CTelnetInterp::ReceivedSE();
  574.     }
  575.     
  576. }
  577.  
  578.  
  579. //    —— Telnet option handling ——
  580.  
  581. /*______________________________________________________________________
  582. **
  583. ** OptionTerminalType
  584. **
  585. **    Interpret an [IAC SB TERMINAL-TYPE ... IAC SE] sequence. Default method always says
  586. **    this is an unknown terminal.
  587. **
  588. */
  589.  
  590. void CTelnetTerminal::OptionTerminalType()
  591.  
  592. {
  593.     char        respondStr[47];
  594.     short    i = 2;
  595.     
  596.     // respond only to TERMINAL-TYPE SEND queries; ignore others
  597.     
  598.     if (sbBfr[1] == 1) {
  599.  
  600.         // build a response string
  601.         
  602.         respondStr[0] = charIAC;
  603.         respondStr[1] = escSB;
  604.         respondStr[2] = optTERMINAL_TYPE;
  605.         
  606.         // switch to next terminal emulation
  607.         
  608.         itsTermMode++;
  609.         if (itsTermMode > termMax)
  610.             itsTermMode = 0;
  611.         // SetTerminalMode(itsTermMode);
  612.         
  613.         // get name of terminal emulation
  614.         
  615.         GetTerminalName(itsTermMode, &respondStr[3]);
  616.         
  617.         // display response if debugging mode enabled
  618.                 
  619.         if (showDebug) {
  620.             PrintDebugStr("{IAC SB TERM-TYPE IS ");
  621.             PrintDebugStr(&respondStr[3]);
  622.             PrintDebugStr(" IAC SE}");
  623.         }
  624.         
  625.         // add end of SB string & send it
  626.         
  627.         while (respondStr[++i])
  628.             ;
  629.         respondStr[i] = charIAC;
  630.         respondStr[i+1] = escSE;
  631.         respondStr[i+2] = '\0';
  632.         *this << respondStr;
  633.     }
  634.     
  635. }
  636.  
  637.  
  638. //    —— terminal emulation handling ——
  639.  
  640. /*______________________________________________________________________
  641. **
  642. ** GetTerminalName
  643. **
  644. **    Return the Internet assigned name for the terminal being used.
  645. **
  646. **        termIndex (short):    the terminal emulation number
  647. **        termStr (char*):    buffer to receive the terminal name (max 40 chars)
  648. **
  649. */
  650.  
  651. void CTelnetTerminal::GetTerminalName(short termIndex, char* termStr)
  652.  
  653. {
  654.     char theTerm[41] = "UNKNOWN";        // for now, all we have is “UNKNOWN”
  655.     BlockMove(theTerm, termStr, 41);
  656. }
  657.  
  658.  
  659.